#include <devices.h>

// CONSOLE /////////////////////////////////////////////////////////////////////

int sys_write_console(int fd, char *buffer, int size)
{
	int i;
	for (i = 0; i < size; i++) printc(buffer[i]);
	return i;
}

void sys_init_console(struct file_operations* ops)
{
  ops->open = sys_open_undefined;
  ops->read = sys_read_undefined;
  ops->write = sys_write_console;
  ops->close = sys_close_undefined;
  ops->unlink= sys_unlink_undefined;
}

// KEYBOARD ////////////////////////////////////////////////////////////////////

char kb_buffer[KEYBOARD_BUFFER_SIZE];
int kb_rd_index = 0;
int kb_wr_index = 0;

int kb_buffered_bytes() {
  return kb_rd_index <= kb_wr_index ? kb_wr_index - kb_rd_index : kb_wr_index + KEYBOARD_BUFFER_SIZE - kb_rd_index;
}

int kb_buffer_full()
{
  return kb_buffered_bytes() == KEYBOARD_BUFFER_SIZE - 1;
}

int kb_buffer_read(char* buffer, int size)
{
  int read = 0;
  if (size >= KEYBOARD_BUFFER_SIZE) {
    size = KEYBOARD_BUFFER_SIZE - 1;
  }
  while (read < size) {
    buffer[read++] = kb_buffer[kb_rd_index++];
    kb_rd_index %= KEYBOARD_BUFFER_SIZE;
  }
  return size;
}

int kb_buffer_write(char c)
{
  if (kb_buffer_full()) {
    return 0;
  }
  kb_buffer[kb_wr_index++] = c;
  kb_wr_index %= KEYBOARD_BUFFER_SIZE;
  return 1;
}

int sys_read_keyboard(int fd, char *buffer, int size)
{
  struct task_struct *ts;
  
  // Si es l'unic procés que ha de llegir i hi ha prou caracters al buffer, els llegeix directament
  if (list_empty(&keyboardqueue) && (size <= kb_buffered_bytes())) {
    kb_buffer_read(buffer, size);
  }
  // Si no es posa a la cua
  else {
    ts = current();
    // El procés 0 no es pot bloquejar!
    if (ts->pid == 0) {
      return -EPERM;
    }
    else {
      ts->kb_params.data_buffer = buffer;
      ts->kb_params.remaining_bytes = size;
      ts->kb_params.read_bytes = 0;
      block_process(ts, &keyboardqueue);
    }
  }
  return size;
}

void sys_init_keyboard(struct file_operations* ops)
{
  ops->open = sys_open_undefined;
  ops->read = sys_read_keyboard;
  ops->write = sys_write_undefined;
  ops->close = sys_close_undefined;
  ops->unlink= sys_unlink_undefined;
}

// OS DEFAULT FUNCTIONS ////////////////////////////////////////////////////////

int sys_open_undefined(int fd)
{
  return 0;
}

int sys_read_undefined(int fd, char* buffer, int size)
{
  return 0;
}

int sys_write_undefined(int fd, char* buffer, int size)
{
  return 0;
}

int sys_close_undefined(int fd)
{
  return 0;
}

int sys_unlink_undefined(struct file* f)
{
  return 0;
}
